package cn.sylinx.hbatis.ext.starter.pool;

import java.lang.reflect.Method;
import java.util.Map;
import java.util.Optional;

import javax.sql.DataSource;

import cn.sylinx.hbatis.db.dialect.DbType;
import cn.sylinx.hbatis.log.GLog;

public abstract class AbstractDataSourceCreator<T extends DataSource> implements DataSourceCreator<T> {

	@SuppressWarnings("unchecked")
	@Override
	public T create(Map<String, Object> dsMap) {

		// dbtype 如果为空，则默认mysql
		String dbType = Optional.ofNullable(dsMap.get("dbtype")).orElse(DbType.MYSQL.getValue()).toString();
		String driverClassName =  Optional.ofNullable(dsMap.get("driver")).orElse("").toString();
		String url = Optional.ofNullable(dsMap.get("url")).orElse("").toString();
		String username = Optional.ofNullable(dsMap.get("username")).orElse("").toString();
		String password = Optional.ofNullable(dsMap.get("password")).orElse("").toString();

		T ds = createBaseDataSource(driverClassName, url, username, password, dbType);
		Map<String, Object> extConfig = (Map<String, Object>) dsMap.get("config");
		if (extConfig != null && !extConfig.isEmpty()) {
			setExtendConfig(ds, extConfig);
		}

		return ds;
	}

	protected void setExtendConfig(T cds, Map<String, Object> extConfig) {

		for (Map.Entry<String, Object> entry : extConfig.entrySet()) {
			String attr = entry.getKey();
			String value = entry.getValue().toString();
			setExtendConfigValue(cds, attr, value);
		}
	}

	private Method getClassSetMethodInner(Class<?> t, String attr, Class<?> parameterType) {

		String methodName = "set" + attr.substring(0, 1).toUpperCase() + attr.substring(1);
		try {
			return t.getDeclaredMethod(methodName, parameterType);

		} catch (Exception e) {
			//GLog.error("在类：{}中没有找到方法：{}, 参数类型：{}", t.getName(), methodName, parameterType.getName());
		}
		return null;
	}

	private Method getClassSetMethod(Class<?> t, String attr) {

		Class<?>[] parameterTypes = new Class<?>[] { int.class, long.class, boolean.class, String.class, Integer.class,
				Long.class, Boolean.class };

		for (Class<?> parameterType : parameterTypes) {
			Method m = getClassSetMethodInner(t, attr, parameterType);
			if (m != null) {
				return m;
			}
		}

		return null;
	}

	private Method getDataSourceSetMethod(Class<?> t, String attr) {

		Class<?> tmpClass = t;
		Method m = getClassSetMethod(tmpClass, attr);
		while (m == null) {
			tmpClass = tmpClass.getSuperclass();
			if ("java.lang.object".equals(tmpClass.getName().toLowerCase())) {
				break;
			}
			m = getClassSetMethod(tmpClass, attr);
		}
		if (m != null) {
			GLog.debug("在类:{}中找到属性:{}", tmpClass.getName(), attr);
		}
		return m;
	}

	protected void setExtendConfigValue(Object t, String attr, String value) {

		try {
			Method m = getDataSourceSetMethod(t.getClass(), attr);
			if (m == null) {
				GLog.error("没有找到配置项:{}", attr);
				return;
			}
			m.setAccessible(true);
			Class<?> type = m.getParameterTypes()[0];
			Object targetValue = value;

			if (type == Boolean.class || type == boolean.class) {
				// 布尔
				targetValue = Boolean.valueOf(value);
			}

			if (type == Integer.class || type == int.class) {
				// int
				targetValue = Integer.valueOf(value);
			}

			if (type == Long.class || type == long.class) {
				// long
				targetValue = Long.valueOf(value);
			}

			if (type == Short.class || type == short.class) {
				// Short
				targetValue = Short.valueOf(value);
			}

			m.invoke(t, targetValue);

		} catch (Exception e) {
			GLog.error("setValue error", e);
		}
	}

	abstract T createBaseDataSource(String driver, String url, String username, String password, String dbType);

}
